#include "PreCompile.hpp"
#include "Perl.hpp"
#include "../EGlib/Spawn.hpp"

namespace BuildNG
{
  //////////////
  // PerlTask
  void PerlTask::init()
  {
    Glib::RefPtr<TaskTypeInfo> type_info(new TaskTypeInfo);
    type_info->set_xml_tag_name("perl");
    type_info->set_create_func_from_ctor<PerlTask>();
    task_types_registry.register_type(type_info);
  }

  void PerlTask::shutdown()
  {
    // nothing
  }

  void PerlTask::load_from_xml(const Xml::Element &xml)
  {
    Xml::Attribute *attr;

    script_file_name = xml.get_attribute_value("script");

    attr = xml.try_get_attribute("args");
    if(attr)
    {
      Glib::ustring args = attr->get_value();
      set_args_from_string(args);
    }

    attr = xml.try_get_attribute("stdin");
    if(attr)
      std_in_file_name = attr->get_value();

    attr = xml.try_get_attribute("stdout");
    if(attr)
      std_out_file_name = attr->get_value();
  }

  void PerlTask::set_args_from_string(const Glib::ustring &str)
  {
    args = parse_command_line_args(str);
  }

  void PerlTask::run(BuildContext &context) const
  {
    Glib::ustring perl_path = Glib::find_program_in_path("perl");
    if(perl_path == "")
      throw PerlTaskException("Couldn't find the perl executable. You probably don't have perl installed.");

    Glib::RefPtr<EGlib::Process> process(new EGlib::Process(perl_path));
    process->set_working_directory(context.get_cur_dir());

    process->add_argument(script_file_name);    

    for(int i = 0;i < (int)args.size();i++)
      process->add_argument(args[i]);

    Glib::ustring abs_in_file = Glib::build_filename(context.get_cur_dir(),std_in_file_name);
    Glib::RefPtr<Glib::IOChannel> stdin_channel = 
      Glib::IOChannel::create_from_file(abs_in_file,"r");
    process->set_stdin_channel(stdin_channel);

    Glib::ustring abs_out_file = Glib::build_filename(context.get_cur_dir(),std_out_file_name);
    Glib::RefPtr<Glib::IOChannel> stdout_channel = 
      Glib::IOChannel::create_from_file(abs_out_file,"w");
    process->set_stdout_channel(stdout_channel);

    process->spawn_sync();
  }

  /////////////
  // Exception stuff
  PerlScriptException::PerlScriptException(const Glib::ustring &script_name,const std::string &error_msg)
    : PerlTaskException(error_msg)
  {
    this->script_name = script_name;

    // error_msg may have \r\n line endings on windows, so we have to read it as if it was a text file, to convert
    // it to a normal c++ string, with just a \n as line ending.
    MemoryInStream stream(error_msg.c_str(),(int)error_msg.length(),0);
    while(1)
    {
      Glib::ustring line;
      if(!stream.read_line(line))
        break;
      error_lines.push_back(line);
    }
  }

  Glib::ustring PerlScriptException::get_message() const
  {
    Glib::ustring ret = "Error running perl script \"" + script_name + "\"";
    if(error_lines.size())
    {
      ret += ":";
      for(int i = 0;i < (int)error_lines.size();i++)
      {
        ret += "\n\t" + error_lines[i];
      }
    }
    else
    {
      ret += ".";
    }
    
    return ret;
  }
}

